using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;

namespace Beetle.Clients;

public class SyncChannel<T> : ISyncChannel where T : Package, new()
{
	public long ReceiveBytes;

	public long SendBytes;

	private bool m_a;

	private bool b;

	private x c;

	private byte[] d = new byte[8192];

	private object e;

	private Package f;

	private Hashtable g = new Hashtable();

	private int h;

	[CompilerGenerated]
	private Socket i;

	[CompilerGenerated]
	private int j;

	[CompilerGenerated]
	private Encoding k;

	public Package Package => f;

	public Socket Socket
	{
		[CompilerGenerated]
		get
		{
			return i;
		}
		[CompilerGenerated]
		private set
		{
			i = value;
		}
	}

	public Hashtable Properties => g;

	public object this[string name]
	{
		get
		{
			return g[name];
		}
		set
		{
			g[name] = value;
		}
	}

	public int Timeout
	{
		[CompilerGenerated]
		get
		{
			return j;
		}
		[CompilerGenerated]
		set
		{
			j = value;
		}
	}

	public Encoding Coding
	{
		[CompilerGenerated]
		get
		{
			return k;
		}
		[CompilerGenerated]
		set
		{
			k = value;
		}
	}

	public bool IsDisposed => this.a;

	public bool Connected => b;

	public SyncChannel()
	{
		Timeout = 0;
		Coding = Encoding.UTF8;
	}

	protected virtual void OnInit()
	{
		f = new T();
		f.GetPools();
		f.CreateWriterReader();
		f.ReceiveMessage = a;
		c = new x(TcpUtils.f);
		f.ReadSinglePackage = true;
	}

	private void a(PacketRecieveMessagerArgs A_0)
	{
		e = A_0.Message;
	}

	protected object OnSend(IMessage data, bool sendOnly = false)
	{
		e = null;
		c.Reset();
		f.MessageWrite(data, c);
		a(c.i());
		if (!sendOnly)
		{
			a();
		}
		return e;
	}

	private void a(ax A_0)
	{
		try
		{
			int num = 0;
			h = 0;
			while (A_0.b != null)
			{
				y y = A_0.b;
				num = 0;
				while (num < y.i)
				{
					int num2 = Socket.Send(y.g, num, y.i - num, SocketFlags.None);
					Interlocked.Add(ref SendBytes, num2);
					if (num2 == 0)
					{
						throw NetTcpException.ClientIsDisposed();
					}
					num += num2;
					h += num2;
				}
				A_0.e();
			}
		}
		catch (Exception innerexception)
		{
			Dispose();
			throw NetTcpException.ClientDataProcessError(innerexception);
		}
		finally
		{
			A_0.d();
		}
	}

	public object Receive()
	{
		e = null;
		a();
		return e;
	}

	public RESULT Receive<RESULT>()
	{
		return (RESULT)Receive();
	}

	private void a()
	{
		try
		{
			if (f.BufferCount > 0)
			{
				f.Import(d, f.BufferOffset, f.BufferCount);
			}
			while (e == null)
			{
				int num = Socket.Receive(d);
				Interlocked.Add(ref ReceiveBytes, num);
				if (num == 0)
				{
					throw NetTcpException.ClientIsDisposed();
				}
				f.Import(d, 0, num);
			}
		}
		catch (NetTcpException ex)
		{
			Dispose();
			throw ex;
		}
		catch (Exception innerexception)
		{
			Dispose();
			throw NetTcpException.ClientDataProcessError(innerexception);
		}
	}

	protected virtual void OnDisposed()
	{
		if (f != null)
		{
			f.Dispose();
		}
		c.Dispose();
		TcpServer.ReleaseSocket(Socket);
	}

	public virtual void SendOnly(object data)
	{
		if (!Connected)
		{
			throw NetTcpException.ClientMustBeConnected();
		}
		if (this.a)
		{
			throw NetTcpException.ClientIsDisposed();
		}
		OnSend((IMessage)Package.WriteCast(data), sendOnly: true);
	}

	public virtual object Send(object data)
	{
		if (!Connected)
		{
			throw NetTcpException.ClientMustBeConnected();
		}
		if (this.a)
		{
			throw NetTcpException.ClientIsDisposed();
		}
		return OnSend((IMessage)Package.WriteCast(data));
	}

	public RESULT Send<RESULT>(object data)
	{
		return (RESULT)Send(data);
	}

	public void Connect(string host, int port)
	{
		if (!b)
		{
			if (!TcpUtils.a)
			{
				throw NetTcpException.NotInitialize();
			}
			if (this.a)
			{
				throw NetTcpException.ClientIsDisposed();
			}
			IPAddress[] hostAddresses = Dns.GetHostAddresses(host);
			Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			Socket.Connect(new IPEndPoint(hostAddresses[0], port));
			Socket.ReceiveTimeout = Timeout;
			Socket.SendTimeout = Timeout;
			OnInit();
			b = true;
		}
	}

	public void Dispose()
	{
		lock (this)
		{
			if (!this.a)
			{
				this.a = true;
				b = false;
				OnDisposed();
			}
		}
	}
}
